-
Notifications
You must be signed in to change notification settings - Fork 32
/
final套餐及常见问题.md
86 lines (42 loc) · 5.67 KB
/
final套餐及常见问题.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
### final相关
#### 区别
**final修饰符(关键字)**
- 被final修饰的类,就意味着不能再派生出新的子类,不能作为父类而被子类继承。因此一个类不能既被abstract声明,又被final声明。
- 被final声明的方法也同样只能使用,即不能方法重写。
- 将变量或方法声明为final,可以保证他们在使用的过程中不被修改。被声明为final的变量必须在声明时给出变量的初始值,而在以后的引用中只能读取。
**finally**
是在异常处理时提供finally块来执行任何清除操作。不管有没有异常被抛出、捕获,finally块都会被执行。
**finalize**
是方法名。java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者被执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
#### finalize详解
**finalize()的功能 :**
一旦垃圾回收器准备释放对象所占的内存空间, 如果对象覆盖了finalize()并且函数体内不能是空的, 就会首先调用对象的finalize(), 然后`在下一次垃圾回收动作发生的时候真正收回对象所占的空间`.
**finalize()调用特点:**
JVM始终只调用一次. 无论这个对象被垃圾回收器标记为什么状态, finalize()始终只调用一次. 但是程序员在代码中主动调用的不记录在这之内.
**finalize()主要使用的方面:**
1. 根据垃圾回收器的第2点可知, `java垃圾回收器只能回收创建在堆中的java对象, 而对于不是这种方式创建的对象则没有方法处理, 这就需要使用finalize()对这部分对象所占的资源进行释放`. 使用到这一点的就是JNI本地对象, 通过JNI来调用本地方法创建的对象只能通过finalize()保证使用之后进行销毁,释放内存
2. 充当保证使用之后释放资源的最后一道屏障, 比如使用数据库连接之后未断开,并且由于程序员的个人原因忘记了释放连接, 这时就只能依靠finalize()函数来释放资源.
3. 《thinking in java》中所讲到的“终结条件”验证, 通过finalize()方法来试图找出程序的漏洞
尽管finalize()可以主动调用, 但是最好不要主动调用, 因为在代码中主动调用之后, 如果JVM再次调用, 由于之前的调用已经释放过资源了,所以二次释放资源就有可能出现导致出现空指针等异常, 而恰好这些异常是没有被捕获的, 那么就造成对象处于被破坏的状态, 导致该对象所占用的某一部分资源无法被回收而浪费.
**尽量避免使用finalize():**
1. finalize()不一定会被调用, 因为java的垃圾回收器的特性就决定了它不一定会被调用
2. 就算finalize()函数被调用, 它被调用的时间充满了不确定性, 因为程序中其他线程的优先级远远高于执行finalize()函数线程的优先级。也许等到finalize()被调用, 数据库的连接池或者文件句柄早就耗尽了.
3. 如果一种未被捕获的异常在使用finalize方法时被抛出,这个异常不会被捕获,finalize方法的终结过程也会终止,造成对象出于破坏的状态。被破坏的对象又很可能导致部分资源无法被回收, 造成浪费.
4. finalize()和垃圾回收器的运行本身就要耗费资源, 也许会导致程序的暂时停止.
**finalize流程:**
当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,
- 若未覆盖,则直接将其回收。
- 否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。
- 执行finalize方法完毕后,GC会再次判断该对象是否可达(因为finalize可能让外部重新引用了该对象,比如让某个类的静态变量引用该对象,从而使该对象复活),若不可达,则进行回收,否则,对象“复活”。
#### 补充
**当在类里定义了一个方法,此时需要线程切换,方法里传的参数 必须用final修饰, why?**
意思是说用匿名内部类实现的Runable的run方法,若在run()里使用外部对象,则必须用final修饰
- 因为使用的变量会作为参数传递到匿名内部类的构造方法,生成的匿名内部类会把其保存为自己的字段,但是在外部看来操作的是同一个对象,所以要保证内部类和外部数据的一致,所以就不可以让生成的匿名内部类修改变量的值。
- 把变量复制一份作为自己的属性还有一个目的,为了保证多线程时,变量的生命周期不会随着创建匿名内部类的方法结束而结束
**如果try里有return语句,还会执行finally里的语句吗?**
会
**finalize里出现了异常,会发生什么? fnalize里面可以开启新的线程吗?**
finalize方法执行终止,未执行的方法不再执行(可能导致部分资源没有释放掉,且JVM不会再次调用该finalize),然后等待JVM下次GC时判断是否重新被重新引用,若没有则进行回收
可以开启新的线程
**finally 中 return 会发生什么?**
如果catch和fianlly里都有return 那么都会返回finally里的return的, 可以从字节码看出来是把catch里return的东西先保存到局部变量表 但是返回的话 在执行finally的代码块时 由于finally要返回的变量在栈顶,所以不管基本类型还是引用,都是返回的finally里的。